/*
 * Copyright (c) 2019.  鼎捷软件股份有限公司.All rights reserved.
 */

package com.digiwin.dap.middleware.service.impl;

import com.digiwin.dap.middleware.entity.BaseEntity;
import com.digiwin.dap.middleware.exception.BusinessException;
import com.digiwin.dap.middleware.exception.OperateException;
import com.digiwin.dap.middleware.service.EntityManagerService;
import com.digiwin.dap.middleware.util.HashUtils;
import com.digiwin.dap.middleware.util.ObjectCopyUtil;
import com.digiwin.dap.middleware.util.SnowFlake;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.Table;
import java.lang.reflect.ParameterizedType;
import java.util.Optional;


/**
 * @author chenxsa
 */
@Service
public abstract class BaseEntityManagerService<T extends BaseEntity> implements EntityManagerService<T> {

    private String tableName;


    /**
     * 获取映射的表
     *
     * @return 表名
     */
    protected String getMappingTableName() {
        if (!StringUtils.isEmpty(tableName)) {
            return tableName;
        }
        Class<T> clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Table table = clazz.getAnnotation(Table.class);
        if (table == null || StringUtils.isEmpty(table.name())) {
            tableName = clazz.getSimpleName();
        } else {
            if (table.name().startsWith("[")) {
                tableName = table.name().replace("[", "`");
                tableName = tableName.replace("]", "`");
            } else {
                tableName = table.name();
            }
        }
        return tableName;
    }

    /**
     * 创建实体
     *
     * @param data 实体对象
     * @return 实体Sid
     */
    @Override
    public long create(T data) {
        if (data.getSid() == 0) {
            data.setSid(SnowFlake.getInstance().newId());
        }
        this.getRepository().save(data);
        return data.getSid();
    }

    /**
     * 根据Sid 查询实体
     *
     * @param sid 实体Sid
     * @return 实体对象
     */
    @Override
    public T findBySid(long sid) {
        return (T) this.getRepository().findById(sid).orElse(null);
    }


    /**
     * 修改实体
     *
     * @param data 实体对象
     */
    @Override
    public void update(T data) {
        this.update(data, false);
    }

    /**
     * 修改实体
     *
     * @param data  实体对象
     * @param force 强制更新
     */
    @Override
    public void update(T data, boolean force) {
        Optional<T> result = this.getRepository().findById(data.getSid());
        if (result.isPresent()) {
            T dbData = result.get();
            if (!force && dbData.getHash()!=null && !dbData.getHash().equals(data.getHash())) {
                if (StringUtils.isEmpty(data.getHash())) {
                    throw new OperateException(String.format("待修改的数据[sid = %s]的hash值为空，无法进行修改", data.getSid()));
                } else {
                    throw new OperateException(String.format("该数据[%s]已被修改，请您重新获取.", data.getSid()));
                }
            }
            data.setHash(HashUtils.hash(HashUtils.objectToString(data)));
            ObjectCopyUtil.mergeObject(data, dbData);
            this.getRepository().save(dbData);
        } else {
            throw new BusinessException("数据已经被删除.sid:" + data.getSid());
        }
    }

    /**
     * 根据sid删除实体
     *
     * @param sid 实体Sid
     */
    @Override
    public void deleteById(long sid) {
        this.getRepository().deleteById(sid);
    }


    /**
     * 根据Sid 禁用实体
     *
     * @param sid 实体Sid
     */
    @Override
    public void disable(long sid) {
        T result = this.findBySid(sid);
        if (result != null) {
            result.setDisabled(true);
            this.update(result);
        } else {
            throw new BusinessException("数据已经被删除.sid:" + sid);
        }
    }

    /**
     * 根据Sid 启用实体
     *
     * @param sid 实体Sid
     */
    @Override
    public void enable(long sid) {
        T result = this.findBySid(sid);
        if (result != null) {
            result.setDisabled(false);
            this.update(result);
        } else {
            throw new BusinessException("数据已经被删除.sid:" + sid);
        }
    }


    /**
     * 当前实体操作服务使用到的dao
     *
     * @return
     */
    protected abstract JpaRepository getRepository();
}